#!/usr/bin/env python3
# -*- coding: utf-8; tab-width: 4; indent-tabs-mode: t -*-

# Copyright (c) 2019-2020 Fpemud <fpemud@sina.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated DocTemplation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.


import os
import sys
import time
import shutil
import random
import selenium
import subprocess
import fake_useragent


class SeleniumUtil:

    # FIXME: not usable
    @staticmethod
    def findMaskElement(driver):
        elements = driver.find_elements(selenium.webdriver.common.by.By.CSS_SELECTOR, "[style*='z-index']")
        if len(elements) > 0:
            max_z_index = max([int(e.value_of_css_property("z-index")) for e in elements])
            max_z_index_element = driver.find_element(selenium.webdriver.common.by.By.CSS_SELECTOR, "[style*='z-index:%d']" % (max_z_index))
            if SeleniumUtil.elementIsMask(max_z_index_element):
                return max_z_index_element
        return None

    # FIXME: not usable
    @staticmethod
    def elementIsMask(driver, elem):
        elem_left_bound = elem.location.get('x')
        elem_top_bound = elem.location.get('y')
        elem_width = elem.size.get('width')
        elem_height = elem.size.get('height')

        win_width = driver.execute_script('return document.documentElement.clientWidth')
        win_height = driver.execute_script('return document.documentElement.clientHeight')

        return all((0 == elem_left_bound,
                    win_width == elem_width,
                    0 == elem_top_bound,
                    win_height == elem_height))

    @staticmethod
    def isElementCompletelyInViewport(driver, elem):
        elem_left_bound = elem.location.get('x')
        elem_top_bound = elem.location.get('y')
        elem_width = elem.size.get('width')
        elem_height = elem.size.get('height')
        elem_right_bound = elem_left_bound + elem_width
        elem_lower_bound = elem_top_bound + elem_height

        win_upper_bound = driver.execute_script('return window.pageYOffset')
        win_left_bound = driver.execute_script('return window.pageXOffset')
        win_width = driver.execute_script('return document.documentElement.clientWidth')
        win_height = driver.execute_script('return document.documentElement.clientHeight')
        win_right_bound = win_left_bound + win_width
        win_lower_bound = win_upper_bound + win_height

        return all((win_left_bound <= elem_left_bound,
                    win_right_bound >= elem_right_bound,
                    win_upper_bound <= elem_top_bound,
                    win_lower_bound >= elem_lower_bound))

    @staticmethod
    def moveElementToCenterOfViewPort(driver, elem):
        driver.execute_script('arguments[0].scrollIntoView({block: "center", inline: "center"})', elem)

    @staticmethod
    def removeElement(driver, elem):
        driver.execute_script('arguments[0].remove()', elem)


class ManpaUtil:

    @staticmethod
    def sleepyZeroToMax(start, waitType):
        i = start
        while True:
            yield i
            if i >= sys.maxsize:
                raise ValueError("value too large")
            ManpaUtil.waitRandomTime(waitType)
            i += 1

    @staticmethod
    def forceDelete(path):
        if os.path.islink(path):
            os.remove(path)
        elif os.path.isfile(path):
            os.remove(path)
        elif os.path.isdir(path):
            shutil.rmtree(path)
        elif os.path.lexists(path):
            os.remove(path)             # other type of file, such as device node
        else:
            pass                        # path does not exist, do nothing

    @staticmethod
    def removeDirContentExclude(dirPath, excludeList):
        for fn in os.listdir(dirPath):
            if fn not in excludeList:
                ManpaUtil.forceDelete(os.path.join(dirPath, fn))

    @staticmethod
    def getRandomUserAgent():
        try:
            dbPath = "/usr/share/fake-useragent-db/fake_useragent_db.json"
            if os.path.exists(dbPath):
                # we don't want fake_useragent access internet
                return fake_useragent.UserAgent(use_external_data=True, cache_path=dbPath).random
            else:
                return fake_useragent.UserAgent().random
        except fake_useragent.errors.FakeUserAgentError:
            return None

    @staticmethod
    def waitRandomTime(waitType):
        if waitType == "1":
            time.sleep(1)
        elif waitType == "short":
            time.sleep(random.randrange(1, 5))
        elif waitType == "middle":
            time.sleep(random.randrange(5, 10))
        elif waitType == "long":
            time.sleep(random.randrange(10, 30))
        else:
            assert False

    @staticmethod
    def createVideoRecordProcess(width, height, colordepth, displayNumber, outputFile):
        cmd = [
            "/usr/bin/ffmpeg",
            "-f",
            "x11grab",
            "-s",
            "%dx%d" % (width, height),
            "-r",
            "%d" % (colordepth),
            "-i",
            ":%d+nomouse" % (displayNumber),
            "-c:v",
            "libx264",
            "-preset",
            "superfast",
            "-pix_fmt",
            "yuv420p",
            "-s",
            "%dx%d" % (width, height),
            "-threads",
            "0",
            "-f",
            "flv",
            outputFile,
        ]
        return subprocess.Popen(cmd)
